package com.appkubes.mall.restful.application.pay.strategy.wxpay.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.appkubes.common.exception.BusinessException;
import com.appkubes.common.utils.data.date.DateUtils;
import com.appkubes.mall.core.entity.MallPayRecord;
import com.appkubes.mall.core.entity.MallSystem;
import com.appkubes.mall.restful.application.pay.strategy.wxpay.model.WXPay;
import com.appkubes.mall.restful.application.pay.strategy.wxpay.model.WXPayUtil;
import com.appkubes.mall.restful.application.pay.strategy.wxpay.model.WxNaturePayConfig;
import com.appkubes.mall.restful.application.system.basic.service.SystemService;
import com.appkubes.mall.restful.application.wx.model.WxModel;
import com.appkubes.mall.restful.application.wx.service.impl.PayRecordServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class WxPayService {

    @Autowired
    private WxModel wxModel;

    @Autowired
    private PayRecordServiceImpl payRecordServiceImpl;

    @Autowired
    SystemService systemService;

    /**
     * 微信支付
     *
     * @param openid
     * @param payAmount
     * @param orderKey
     * @return
     */
    public Map<String, String> pay(String openid, BigDecimal payAmount, String orderKey, String type, String body, String appType) throws BusinessException {
        if (payAmount.compareTo(BigDecimal.ZERO) != 1) {
            throw new BusinessException("支付金额有误");
        }

        String outTradeNo = DateUtils.parseDateToStr(new Date(), DateUtils.DATE_TIME_FORMAT_YYYYMMDDHHMISSSSS) + "" + (int) ((Math.random() * 9 + 1) * 100000);
        List<MallPayRecord> list = payRecordServiceImpl.queryAll(" source_key='" + orderKey + "' and callback_time>0 order by create_time desc");
        if (list.size() > 0) {
            MallPayRecord record = list.get(0);
            if (!StringUtils.isEmpty(record.getCallbackXml())) {
                JSONObject jsonobj = JSON.parseObject(record.getCallbackXml());
                if (!StringUtils.isEmpty(jsonobj.getString("result_code"))) {
                    if (jsonobj.getString("result_code").equals("SUCCESS")) {
                        throw new BusinessException("该单已支付");
                    }
                }
            }
        }
        MallPayRecord payRecord = new MallPayRecord();
        payRecord.setSourceType(type);
        payRecord.setSourceKey(orderKey);
        payRecord.setPayMoney(payAmount);
        payRecord.setPayTime(DateUtils.DateToTimestamp(new Date()));
        payRecord.setOpenid(openid);
        payRecord.setNo(outTradeNo);
        payRecordServiceImpl.add(payRecord);

        Map<String, String> attachMap = new HashMap<>();
        attachMap.put("payrecord_key", payRecord.getPayrecordKey());

        try {
            WxNaturePayConfig wxNaturePayConfig = new WxNaturePayConfig(this.wxMap(appType));
            WXPay wxPay = new WXPay(wxNaturePayConfig);
            String notifyUrl = wxNaturePayConfig.getNotify();
            //根据微信支付api来设置
            Map<String, String> data = new HashMap<>();
            data.put("attach", JSON.toJSONString(attachMap));
            data.put("appid", wxNaturePayConfig.getAppID());
            data.put("mch_id", wxNaturePayConfig.getMchID());         //商户号
            data.put("trade_type", wxNaturePayConfig.getTradeType());  //支付场景 APP 微信app支付 JSAPI 公众号支付  NATIVE 扫码支付
            data.put("notify_url", notifyUrl);                     //回调地址
            data.put("spbill_create_ip", "127.0.0.1");             //终端ip

            data.put("total_fee", payAmount.multiply(BigDecimal.valueOf(100)).toString());
            data.put("fee_type", "CNY");                           //默认人民币
            data.put("out_trade_no", outTradeNo);   //交易号
            data.put("body", body);
            if (!appType.equals("2") && !appType.equals("3")) {
                data.put("openid", openid);
            }
            data.put("nonce_str", System.currentTimeMillis() + "" + (int) ((Math.random() * 9 + 1) * 100000));   // 随机字符串小于32位
            String s = WXPayUtil.generateSignature(data, wxNaturePayConfig.getKey());  //签名
            data.put("sign", s);
            Map<String, String> respData = wxPay.unifiedOrder(data);
            //if (respData!=null) return respData;
            Map<String, String> repData = new HashMap<>();
            if (respData.get("return_code").equals("SUCCESS")) {
                //app支付
                if (appType.equals("2")) {
                    repData.put("appid", wxNaturePayConfig.getAppID());
                    repData.put("partnerid", wxNaturePayConfig.getMchID());
                    repData.put("noncestr", respData.get("nonce_str"));
                    repData.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
                    repData.put("package", "Sign=WXPay");
                    repData.put("prepayid", respData.get("prepay_id"));
                    String sign = WXPayUtil.generateSignature(repData, wxNaturePayConfig.getKey()); //签名
                    repData.put("sign", sign);
                    repData.put("notify", wxNaturePayConfig.getNotify());
                    return repData;
                } else if (appType.equals("3")) {
                    //h5(外部浏览器)
                    repData.put("appid", wxNaturePayConfig.getAppID());
                    repData.put("noncestr", respData.get("nonce_str"));
                    repData.put("partnerid", wxNaturePayConfig.getMchID());
                    repData.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
                    repData.put("package", "Sign=WXPay");
                    repData.put("prepayid", respData.get("prepay_id"));
                    repData.put("mweb_url", respData.get("mweb_url"));
                    String sign = WXPayUtil.generateSignature(repData, wxNaturePayConfig.getKey()); //签名
                    repData.put("sign", sign);
                    return repData;
                } else if (appType.equals("4")) {
                    //h5(公众号和微信内置浏览器)
                    repData.put("appId", wxNaturePayConfig.getAppID());
                    repData.put("nonceStr", respData.get("nonce_str"));
                    repData.put("package", "prepay_id=" + respData.get("prepay_id"));
                    repData.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
                    repData.put("signType", "MD5");
                    String sign = WXPayUtil.generateSignature(repData, wxNaturePayConfig.getKey()); //签名
                    repData.put("paySign", sign);
                    repData.put("prepay_id", respData.get("prepay_id"));
                    return repData;
                } else {
                    //小程序
                    repData.put("appId", wxNaturePayConfig.getAppID());
                    repData.put("nonceStr", respData.get("nonce_str"));
                    repData.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
                    repData.put("package", "prepay_id=" + respData.get("prepay_id"));
                    repData.put("signType", "MD5");
                    String sign = WXPayUtil.generateSignature(repData, wxNaturePayConfig.getKey()); //签名
                    repData.put("paySign", sign);
                    repData.put("prepay_id", respData.get("prepay_id"));
                    return repData;
                }
            }
            return respData;
        } catch (Exception e) {
            throw new BusinessException("微信支付失败");
        }
    }

    private Map<String, String> wxMap(String appType) {
        Map<String, String> map = new HashMap<>();
        MallSystem system = systemService.getCur();
        map.put("mchId", system.getMchid());
        if (appType.equals("2")) {
            map.put("appId", system.getAppid());
            map.put("wxKey", system.getWxkey());
            map.put("notify", wxModel.getNotifyBaseUrl() + "/wx/paycallbackApp");
            map.put("tradeType", "APP");
        } else if (appType.equals("3")) {
            map.put("appId", system.getServerAppid());
            map.put("wxKey", system.getWxkey());
            map.put("notify", wxModel.getNotifyBaseUrl() + "/wx/paycallbackh5");
            map.put("tradeType", "MWEB");
        } else if (appType.equals("4")) {
            map.put("appId", system.getServerAppid());
            map.put("wxKey", system.getWxkey());
            map.put("notify", wxModel.getNotifyBaseUrl() + "/wx/paycallbackjsapi");
            map.put("tradeType", "JSAPI");
        } else {
            map.put("appId", system.getAppid());
            map.put("wxKey", system.getWxkey());
            map.put("notify", wxModel.getNotifyBaseUrl() + "/wx/paycallback");
            map.put("tradeType", "JSAPI");
        }
        return map;
    }
}
